package com.jishuo.nontax.bfc.service;

import com.github.pagehelper.PageHelper;
import com.jishuo.base.bean.BaseResult;
import com.jishuo.base.bean.ErrorCodeEnum;
import com.jishuo.base.bean.Pagination;
import com.jishuo.base.config.NonTaxConfig;
import com.jishuo.base.service.SequenceService;
import com.jishuo.base.util.CommonUtil;
import com.jishuo.base.util.ExportSXSSFUtil;
import com.jishuo.base.util.StringUtil;
import com.jishuo.nontax.bean.bank.BackPayBill;
import com.jishuo.nontax.bean.bank.BackPayBillBackOut;
import com.jishuo.nontax.bean.bank.OnlineOrder;
import com.jishuo.nontax.bean.message.GetBackBill;
import com.jishuo.nontax.bean.message.SetBackBill;
import com.jishuo.nontax.bean.vo.BackpaybillVO;
import com.jishuo.nontax.bfc.dao.BackBillMapper;
import com.jishuo.nontax.bfc.pzk.PzkService;
import com.jishuo.nontax.bfc.tlq.MessageFactory;
import com.jishuo.nontax.bfc.tlq.MessageService;
import com.jishuo.nontax.util.BillStateUtil;
import com.jishuo.nontax.util.PzkUtils;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.simpleframework.xml.Serializer;
import org.simpleframework.xml.core.Persister;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * @author :hanlipeng
 * @description :
 * @create :2022-12-20 10:55:00
 */
@Service
public class BackBillService {
    private static Logger logger = LoggerFactory.getLogger(BackBillService.class);

    @Resource
    private BackBillMapper backBillMapper;
    @Resource
    private SequenceService sequenceService;
    @Resource
    private MessageService messageService;
    @Resource
    private NonTaxConfig nonTaxConfig;
    @Resource
    private OnlineOrderService onlineOrderService;
    @Resource
    private PzkService pzkService;
    @Resource
    private PzkUtils pzkUtils;

    private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    /**
     * 获得缴款书列表
     *
     * @return
     */
    public List<BackpaybillVO> findBackPayBillPage(BackpaybillVO backpaybillVO, Pagination pagination) {
        // 当单页条数大于零时，启用分页
        if (pagination.getRows() > 0) PageHelper.startPage(pagination.getPage(), pagination.getRows());
        return this.backBillMapper.findBackPayBillPage(backpaybillVO);
    }

    /**
     * @author hlp
     * @date 2023/2/14 16:31
     * @Description: 获取退付书单据信息
     */
    public BaseResult getBackbill(String backbillnum) {
        try {
            //xml解析器
            Serializer serializer = new Persister();
            //xml转换器
            StringWriter sw = new StringWriter();

            BackpaybillVO billVo = backBillMapper.findBackBillInfo(backbillnum);

            //如果单据存在，已缴费  直接返回
            if (billVo != null && (billVo.getBillstate() == 3 || billVo.getIsbankaffirm() == 1)) {
                billVo.setBillstate(3);
                BackPayBill backPayBill = billVo.getBackPayBill();
                serializer.write(backPayBill, sw);
                return new BaseResult(sw.toString());
            }

            /*
             *  如果不存在添加数据
             *  如果存在修改messageid
             */
            long messageid = sequenceService.getNextSeq("ELEMESSAGESEQ");
            if (billVo == null) {
                billVo = new BackpaybillVO();
                billVo.setBackbillnum(backbillnum);
                billVo.setMessageid(messageid);
                billVo.setKeyword(0l);
                billVo.setBackbillid(sequenceService.getNextSeq("FSBACKBILLSEQ"));
                backBillMapper.insertBackpaybill(billVo);
            } else {
                billVo.setMessageid(messageid);
                backBillMapper.updateMsgBackBill(billVo);
            }

            //获取缴款书对象
            GetBackBill getbackbill = new GetBackBill();
            getbackbill.setBackbillnum(backbillnum);
            getbackbill.setKeyword("0");
            //发送到财政
            boolean suc = messageService.sendAndRecvMessage("GETBACKBILL", messageid, getbackbill, "2.0");
            if (suc) {
                //获取缴款书
                BackPayBill bill = backBillMapper.findBackBillInfo(getbackbill.getBackbillnum()).getBackPayBill();
                serializer.write(bill, sw);
                return new BaseResult(sw.toString());
            }
            return new BaseResult(ErrorCodeEnum.BILL_GET_TIMEOUT);

        } catch (Exception e) {
            logger.info("处理获取退付书失败：" + e.toString(), e);
            return new BaseResult(ErrorCodeEnum.UNKNOWN_ERR);
        }
    }

    /**
     * @author hlp
     * @date 2023/2/14 17:29
     * @Description: 退付书单据缴费
     */
    public BaseResult setBackBillDeposit(BackpaybillVO backPayBill, String paychnl) {
        // 参数检查
        String retMsg = "";
        if (StringUtil.isEmpty(backPayBill.getBackbillnum())) {
            retMsg += "票号未填写；";
        } else if (StringUtil.isEmpty(backPayBill.getDealdate())) {
            retMsg += "缴费时间未填写；";
        } else if (StringUtil.isEmpty(backPayBill.getBankaffirm())) {
            retMsg += "交易流水号未填写；";
        }
        if (!"".equals(retMsg)) {
            logger.info("缴费参数错误。" + retMsg);
            return new BaseResult(ErrorCodeEnum.PARAM_ERR);
        }

        BackpaybillVO bill = backBillMapper.findBackBillInfo(backPayBill.getBackbillnum());
        //判断单据信息是否存在
        if (bill == null) {
            logger.info("单据缴款号不存在（票号：" + backPayBill.getBackbillnum() + "）");
            return new BaseResult(ErrorCodeEnum.BILL_NOT_FOUND);
        }

        // 判断是否已缴费
        if (bill.getIsbankaffirm() == 1) {
            // 日期一致的允许二次提交
            if (!CommonUtil.checkPaybankdt(bill.getDealdate(), backPayBill.getDealdate()))
                return new BaseResult(ErrorCodeEnum.BILL_PAYED);
        } else if (bill.getBillstate() == 3) {
            return new BaseResult(ErrorCodeEnum.BILL_PAYED);
        }

        try {
            bill.setIsbankaffirm(1);
            bill.setSendtime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
            bill.setBankaffirm(backPayBill.getBankaffirm());
            bill.setBankstation(backPayBill.getBankstation());
            bill.setDealdate(backPayBill.getDealdate());
            bill.setHxbankaffirm(backPayBill.getBankaffirm());
            int n = backBillMapper.updateBackBillBankAffirm(bill);

            OnlineOrder oo = new OnlineOrder();
            oo.setBillnum(bill.getBackbillnum());
            oo.setAmt(bill.getFund().toPlainString());
            oo.setBankaffirm(bill.getBankaffirm());
            oo.setBilltype(6);
            oo.setPaybankdt(bill.getDealdate());
            oo.setPaychnl(paychnl);
            oo.setPayee(bill.getDrawman());
            oo.setPayeeaccount(bill.getDrawaccount());
            oo.setPayer(bill.getAccountname());
            oo.setPayeraccount(bill.getAccountcode());
            oo.setPaytype(2);
            onlineOrderService.saveOnlineOrder(oo);

            if (n < 1) {
                return new BaseResult("3002", "更新退付书失败（" + backPayBill.getBackbillnum() + "）");
            }

            Object obj = MessageFactory.setBackBillDeposit(bill);
            long messageid = sequenceService.getNextSeq("ELEMESSAGESEQ");
            //发送到财政
            messageService.sendMessage("SETBACKBILLDEPOSIT", messageid, obj, "2.0");
            // 写凭证
            pzkService.savePzmsg("SETBACKBILLPZK", pzkUtils.getBackBill(bill));

            return new BaseResult();
        } catch (Exception e) {
            logger.info("退付书收款失败：" + e.toString());
            return new BaseResult("3100", "退付书收款异常" + e.getMessage());
        }
    }

    /**
     * 财政返回票据，入库
     * @param data 财政报文
     * @param billstate 票据状态
     * @param sn 消息sn
     */
    public void setBackBill(String data, int billstate, String sn) {
        if (billstate == 1) {
            try {
                //xml解析器
                Serializer serializer = new Persister();
                //返回缴款书对象
                SetBackBill setbackbill = serializer.read(SetBackBill.class, new StringReader(data));
                BackpaybillVO vo = new BackpaybillVO(setbackbill);
                vo.setBillstate(billstate);
                vo.setIssend(2);
                backBillMapper.updateBackPayBill(vo);
            } catch (Exception e) {
                logger.info("处理获取退付书失败：" + e, e);
            }
        } else if (billstate > 1) {
            long messageid = Long.parseLong(sn.substring(sn.indexOf("-") + 1));
            backBillMapper.updateBillState(messageid, billstate);
        }
    }

    public BaseResult sendBackpaybill(String billnum, BackpaybillVO vo) {
        if (vo == null) vo = backBillMapper.findBackBillInfo(billnum);
        if (vo.getIsbankaffirm() == 0) return new BaseResult(ErrorCodeEnum.CUSTOM_ERR.getCode(), "不允许发送未缴费单据");

        // 发送财政
        try {
            Object obj = MessageFactory.setBackBillDeposit(vo);
            long messageid = sequenceService.getNextSeq("ELEMESSAGESEQ");
            messageService.sendMessage("SETBACKBILLDEPOSIT", messageid, obj, "2.0");
            return new BaseResult();
        } catch (Exception e) {
            logger.info("发送财政失败。" + e.toString(), e);
            return new BaseResult(ErrorCodeEnum.TLQ_ERR);
        }
    }

    /**
     * 发送财政
     * @param billids 单据列表
     * @return
     */
    public BaseResult sendBackpaybill(String billids) {
        long[] ids = CommonUtil.getIdsLong(billids);
        if (ids.length == 0) return new BaseResult(ErrorCodeEnum.PARAM_ERR);
        List<BackpaybillVO> backList = backBillMapper.findBackPayBill(ids);
        for (BackpaybillVO vo : backList) {
            sendBackpaybill(vo.getBackbillnum(), vo);
        }
        return new BaseResult();
    }

    /**
     * 冲销
     * @param billids
     * @param usercode
     * @return
     */
    public BaseResult cleanBackpaybill(String billids, String usercode) {
        long[] ids = CommonUtil.getIdsLong(billids);
        if (ids.length == 0) return new BaseResult(ErrorCodeEnum.PARAM_ERR);
        List<BackpaybillVO> backList = backBillMapper.findBackPayBill(ids);

        Calendar cal = Calendar.getInstance();
        String cxTime = sdf.format(cal.getTime());
        cal.add(Calendar.MINUTE, 0 - nonTaxConfig.CxTime);
        String chkTime = sdf.format(cal.getTime());

        String errinfo = "";
        for (BackpaybillVO vo : backList) {
            if (vo.getSendtime() == null || vo.getSendtime().length() == 0 || chkTime.compareTo(vo.getSendtime()) < 0) {
                setBackBillBackOut(cxTime, usercode, vo);
                backBillMapper.backOutBackBill(vo.getBackbillid());
            } else {
                errinfo += vo.getBackbillnum() + ",";
            }
        }
        if (!errinfo.equals("")) {
            errinfo += "超时冲销失败,其他单据冲销成功!";
            return new BaseResult(ErrorCodeEnum.CUSTOM_ERR.getCode(), errinfo);
        } else {
            errinfo = "冲销成功";
            return new BaseResult(ErrorCodeEnum.SUCCESS.getCode(), errinfo);
        }
    }

    private BaseResult setBackBillBackOut(String backoutdt, String backoutname, BackpaybillVO backpaybillVO) {
        try {
            BackPayBillBackOut out = new BackPayBillBackOut();
            out.setBackbillnum(backpaybillVO.getBackbillnum());
            out.setBackoutdt(backoutdt);
            out.setBackoutname(backoutname);
            out.setBankaffirm(backpaybillVO.getBankaffirm());
            out.setBankid(StringUtil.toStr(backpaybillVO.getBankid()));
            out.setBankstation(backpaybillVO.getBankstation());
            out.setCantonid(StringUtil.toStr(backpaybillVO.getCantonid()));
            out.setDrawaccount(backpaybillVO.getDrawaccount());
            out.setDrawbank(backpaybillVO.getDrawbank());
            out.setDrawman(backpaybillVO.getDrawman());
            out.setFund(backpaybillVO.getFund().toPlainString());
            out.setItemid(StringUtil.toStr(backpaybillVO.getItemid()));
            out.setUnitid(StringUtil.toStr(backpaybillVO.getUnitid()));
            out.setKeyword(StringUtil.toStr(backpaybillVO.getKeyword()));
            out.setRemark("冲销");

            long messageid = sequenceService.getNextSeq("ELEMESSAGESEQ");

            //发送到财政
            messageService.sendMessage("SETBACKBILLBACKOUT", messageid, out, "2.0");
            // 写凭证
            pzkService.savePzmsgOut(BillStateUtil.BillType_BackBill, backpaybillVO.getBackbillnum(), backpaybillVO.getBankaffirm());
            return new BaseResult();
        } catch (Exception e) {
            logger.info("退付书冲销失败：" + e.toString(), e);
            return new BaseResult();
        }
    }

    /**
     * 缴款书列表导出
     *
     * @return
     */
    public void backPayBillExport(long bankid, String paybankdt, HttpServletResponse response) throws IOException {
        if (bankid == 0 || StringUtil.isEmpty(paybankdt)) return;

        BackpaybillVO vo = new BackpaybillVO();
        vo.setBankid(bankid);
        vo.setDealdate(paybankdt);

        List<BackpaybillVO> list = backBillMapper.findBackPayBillPage(vo);
        String[] headers = {"主流水号", "退付书票号", "区划id", "区划编码", "区划名称", "单位id", "单位编码", "单位名称", "银行id", "缴款人账户", "缴款人账号", "缴款人开户行", "收款人", "收款人账号", "收款人开户行", "项目id", "项目编码", "项目名称", "银行收款时间", "银行网点", "银行交易流水号", "发送状态", "余额", "_status", "发送时间", "银行核心交易流水号", "是否发送"};
        //数据键名或者MODEL类字段名
        String[] col = {"BACKBILLID", "BACKBILLNUM", "CANTONID", "cantoncode", "cantonname", "unitid", "unitcode", "unitname", "bankid", "accountname", "accountcode", "bankname", "payee", "payeeaccount", "payeebankname", "itemid", "itemcode", "itemname", "paybankdt", "bankstation", "bankaffirm", "billstate", "fund", "__status", "sendtime", "hxbankaffirm", "issend"};
        ExportSXSSFUtil ex = new ExportSXSSFUtil();
        SXSSFWorkbook workbook = ex.exportExcelSXSSF("退付书列表", headers, col, list, null);
        response.setContentType("application/vnd.ms-excel");
        response.setHeader("Content-Disposition", "attachment;filename=" + new String(("退付书列表.xls").getBytes(), "iso-8859-1"));
        OutputStream ouputStream = response.getOutputStream();
        workbook.write(ouputStream);
        ouputStream.flush();
        ouputStream.close();

    }

}
